﻿namespace Example.Cryptography
{
    using System;
    using System.Security.Cryptography;

    using Xunit;

    public class RsaSettingsFacts
    {
        private const string PrivateKey = "<RSAKeyValue>"
                                          + "<Modulus>2EeWzHMSn533eyrkdaBS7MOCcDwCjmtIw+NnTXe+PvGch3gcgrZEIbTRmLDOnwJti/EnBccvbyDJEoKvV/Yigz/0V/hlACVrdY+XYmEgObVtR4RIXFUu6TtL1EVQWGV4OwZYDifn1LUt1GCFM386JIiQaeE3JHL029S4kJh0GTU=</Modulus>"
                                          + "<Exponent>AQAB</Exponent>"
                                          + "<P>/GPKc3gcZQ3n9guwkdO7NtZaLZssW0LHc5aZpQcZPBQYuy+OdjRrSP3cuPUqLi3MaFW8tf6jZ6fDVwceqS7Z6w==</P>"
                                          + "<Q>21+RoUsaKyRO8s92PxhvpHFAl0wPlXxlIlMqgv0r6JQUaMRhtWtu1YccYdBqPCtDyeDrPyM491hAg7m50QHxXw==</Q>"
                                          + "<DP>L9+B1DsxL53epNX8zPxbY4BvJH1tgXX+PReQ1zOsfq/VLRRNMnCo9PRqPI8MTCwVvKienerJ9exlagmIsFCZtw==</DP>"
                                          + "<DQ>jPnJmKGu23Kl2ZxBHSMS+9Zb797NVP9v7rMLaspP4VLoGru5HuE/hLEjKCjLXIdhNOb5xsVX4nwwWXaNVyeseQ==</DQ>"
                                          + "<InverseQ>JcvdRtJ+v/5uuskUq2CsyBRTlSnc6fGIP73QkIya0Yo3xiKTGs/ZmLdSx9iOTsRXR93/N9j6S3nDWX+7TEijMw==</InverseQ>"
                                          + "<D>Zp+pfT+I8bYp7QaQOwQk9PVcGldPOzbK4zAvH0IXQpSwmlMy7A8CSyAaaCJVGHw1cLavtn0qE8fxwNfDzbAb9V10CMGdTiKBdCn3nSeym+2E/PAebRlbL58l5dGQ/H2/eycWLGg92zjLzKfO4fQtTNIgavTTsEzP2/9fPL0XYI0=</D>"
                                          + "</RSAKeyValue>";

        private const string PublicKey = "<RSAKeyValue>"
                                         + "<Modulus>2EeWzHMSn533eyrkdaBS7MOCcDwCjmtIw+NnTXe+PvGch3gcgrZEIbTRmLDOnwJti/EnBccvbyDJEoKvV/Yigz/0V/hlACVrdY+XYmEgObVtR4RIXFUu6TtL1EVQWGV4OwZYDifn1LUt1GCFM386JIiQaeE3JHL029S4kJh0GTU=</Modulus>"
                                         + "<Exponent>AQAB</Exponent>"
                                         + "</RSAKeyValue>";

        [Fact]
        public void Roundtrip()
        {
            const string expected = "test";

            var ciphertext = new RsaSettings(PublicKey).Encrypt(new RsaPlaintext(expected));
            var plaintext = new RsaSettings(PrivateKey).Decrypt(ciphertext);

            var actual = plaintext.ToString();

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void Roundtrip_Fresh()
        {
            const string expected = "test";
            string actual;

            using (var rsa = RSA.Create())
            {
                var ciphertext = new RsaSettings(rsa.ToXmlString(false)).Encrypt(new RsaPlaintext(expected));
                var plaintext = new RsaSettings(rsa.ToXmlString(true)).Decrypt(ciphertext);
                actual = plaintext.ToString();
            }

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void ctor_stringNull()
        {
            Assert.Throws<ArgumentNullException>(() => new RsaSettings(null));
        }

        [Fact]
        public void ctor_string_private()
        {
            Assert.NotNull(new RsaSettings(PrivateKey));
        }

        [Fact]
        public void ctor_string_public()
        {
            Assert.NotNull(new RsaSettings(PublicKey));
        }

        [Fact]
        public void op_Decrypt_RsaCiphertext()
        {
            var ciphertext = new RsaSettings(PublicKey).Encrypt(new RsaPlaintext("test"));

            Assert.NotNull(new RsaSettings(PrivateKey).Decrypt(ciphertext));
        }

        [Fact]
        public void op_Decrypt_RsaCiphertextNull()
        {
            Assert.Throws<ArgumentNullException>(() => new RsaSettings(PrivateKey).Decrypt(null));
        }

        [Fact]
        public void op_Encrypt_RsaCiphertext()
        {
            var plaintext = new RsaPlaintext("test");

            Assert.NotNull(new RsaSettings(PublicKey).Encrypt(plaintext));
        }

        [Fact]
        public void op_Encrypt_RsaCiphertextNull()
        {
            Assert.Throws<ArgumentNullException>(() => new RsaSettings(PublicKey).Encrypt(null));
        }
    }
}